﻿using System;
using System.Collections.Generic;
using System.Linq;
using DomenModel;
using Infrastructure.Repositories;
using Model.Service;
using Model.Repositories;
using Model.Repositories.Interfaces;
using System.Linq.Expressions;

namespace Infrastructure.Service
{
    public class ItemService : IItemService
    {
        
        private IItemCrud _dbItems;
       
        private ICrudItemDimension _dbItemDimensions;
        public ItemService(IItemCrud _dbItems, ICrudItemDimension _dbItemDimensions)
        {
            this._dbItems = _dbItems;
            this._dbItemDimensions = _dbItemDimensions;
        }

       
        public List<Item> GetItems()
        {
           
            var items = _dbItems.GetCollection();
            return items;
        }

           
        public bool CreateItem(Item item)
        {
            var check = _dbItems.GetByName(item.Name);
            if (check == null)
            {
                _dbItems.Save(item);
                return true;
            }
            return false;

            
        }

        public Item GetItemById(int id)
        {
           return _dbItems.GetById(id);
        }

        public ItemDimension GetItemDimensionById(int id)
        {
            return _dbItemDimensions.GetById(id);
        }


     
        public void EditItem(Item item)
        {
           
            _dbItems.Update(item);
            
        }

        public Item GetItem(string item)
        {
           
            var getItem = _dbItems.GetByName(item);
            return getItem;
        }

        public bool DeactivateItem(string Name)
        {
            _dbItems.Deactivate(Name);
            return true;
        }
        public bool DeactivateItemById(int id)
        {
            _dbItems.DeactivateById(id);
            return true;
        }

        public bool DeleteItem(int id)
        {
            
            _dbItems.Delete(id);
            return true;
        }

        public void AddNewItemDimension(ItemDimension item)
        {
          
            _dbItemDimensions.Save(item);
        }
        
        public void EditItemDimension(ItemDimension itemDim)
        {
           
            _dbItemDimensions.Update(itemDim);
        }

        public long GetCountOfItems()
        {
            var count = _dbItems.GetCountOfItems();
            return count;
        }

        public long GetCountOfItems(string searchString, string listSelectField, string listSelectCondition)
        {
            var filterExpression = Filter(searchString, listSelectField, listSelectCondition);
            var count = _dbItems.GetCountOfItems(filterExpression);
            return count;
        }

        private Expression<Func<Item, bool>> Filter(string searchString, string listSelectField, string listSelectCondition)
        {
            var param = Expression.Parameter(typeof(Item), "u");
            MemberExpression prop;
            switch (listSelectField)
            {
                case "Price":
                    prop = Expression.Property(param, typeof(ItemDimension).GetProperty("ItemDimensions.Price"));
                    break;

                case "Description":
                    prop = Expression.Property(param, typeof(Item).GetProperty("Description"));
                    break;

                default:
                    prop = Expression.Property(param, typeof(Item).GetProperty("Name"));
                    break;
                    
            }

            string selectedCondition;
            switch (listSelectCondition)
            {
                case "starts with":
                    selectedCondition = "StartsWith";
                    break;
                
                default:
                    selectedCondition = "Contains";
                    break;
            }

            MethodCallExpression startsWith = Expression.Call(
                prop,
                typeof(String).GetMethod(selectedCondition, new Type[] { typeof(String) }),
                Expression.Constant(searchString)
                );

            return Expression.Lambda<Func<Item, bool>>(startsWith, param);

        }

        public List<Item> GetPaginationListOfItems(int page, int itemsOnPage, string orderItemsBy)
        {
            Expression<Func<Item, string>> predicate;

            orderItemsBy = orderItemsBy ?? "ItemName";
            bool descending = false;

            string[] st = orderItemsBy.Split(' ');
            if (st.Length == 2) descending = true;

            switch (st[0])
            {
                case "ItemName":
                    predicate = p => p.Name;
                    break;
                case "Description":
                    predicate = p => p.Description;
                    break;
                
                
                default:
                    predicate = p => p.Name;
                    break;
            }
            var list = _dbItems.GetListForPagination(page, itemsOnPage, predicate, descending);
            return list;
        }

        public List<Item> GetPaginationWithFilter(int page, int itemsOnPage, string orderItemsBy, string searchString, string listSelectField, string listSelectCondition)
        {
            Expression<Func<Item, string>> predicateSortBy;

            orderItemsBy = orderItemsBy ?? "ItemName";

            bool descending = false;

            string[] st = orderItemsBy.Split(' ');
            if (st.Length == 2) descending = true;

            switch (st[0])
            {
                case "ItemName":
                    predicateSortBy = p => p.Name;
                    break;
                case "Description":
                    predicateSortBy = p => p.Description;
                    break;
                
                default:
                    predicateSortBy = p => p.Name;
                    break;
            }

            var filterExpression = Filter(searchString, listSelectField, listSelectCondition);

            var list = _dbItems.GetListForPaginationWithFilter(page, itemsOnPage, filterExpression, predicateSortBy, descending);
            return list;
        }

    }
}
